package com.zhiyou.hospital.ssh.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ModelDriven;
import com.zhiyou.hospital.ssh.model.PermissionModel;
import com.zhiyou.hospital.ssh.model.RoleModel;
import com.zhiyou.hospital.ssh.model.UserModel;
import com.zhiyou.hospital.ssh.result.LoginResult;
import com.zhiyou.hospital.ssh.service.IBaseService;
import com.zhiyou.hospital.ssh.service.IUserService;
import com.zhiyou.hospital.ssh.util.LogHelper;
import com.zhiyou.hospital.ssh.util.LogUtil;
import com.zhiyou.hospital.ssh.util.VerifyCodeUtil;
import jdk.internal.util.xml.impl.Input;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.dispatcher.HttpParameters;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by zhouyanchao on 2017/10/16.
 * Descr: 处理首页跳转、用户登录退出等
 */
@ParentPackage("defaultPackage")
@Namespace("/")
public class HomeAction extends BaseAction{
	static LogUtil log = LogHelper.getLogUtilInstance(HomeAction.class);

	@Autowired
	IUserService userService;


	InputStream fileInput;

	/**
	 * Created by zhouyanchao on 2017/10/16
	 * Descr: 系统首页跳转,如果没有公开的首页，可以跳转到登录页面去
	 *
	 */
	@Action(value = "index",results = {@Result(name = "success",location = "/WEB-INF/jsp/test.jsp")})
	public String index(){

		return SUCCESS;
	}

	/**
	 * Created by zhouyanchao on 2017/10/17
	 * Descr: 返回登录验证码信息
	 *
	 */
	@Action(value = "loginverify")
	public String loginVerify(){
		HttpServletResponse response = ServletActionContext.getResponse();
		HttpServletRequest request = ServletActionContext.getRequest();

		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		response.setContentType("image/jpeg");

		//生成随机字串
		String verifyCode = VerifyCodeUtil.generateVerifyCode(4);
		//存入会话session
		HttpSession session = request.getSession(true);
		//删除以前的
		session.removeAttribute(VERIFY_LOGIN);
		session.setAttribute(VERIFY_LOGIN, verifyCode.toLowerCase());
		//生成图片
		int w = 100, h = 30;
		try {
			VerifyCodeUtil.outputImage(w, h, response.getOutputStream(), verifyCode);
		}catch (Exception e){
			log.e(e);
		}

		//不需要返回结果
		return  NONE;
	}

	/**
	 * Created by zhouyanchao on 2017/10/16
	 * Descr: 登录请求，方法内部判断是get还是post请求，分开处理
	 *
	 * get请求处理登录页面的返回
	 * post请求处理登录信息，使用json返回登录结果
	 *
	 */
	@Action(value = "login",
	results = {@Result(name = "json",type = "json",params = {"root","result"}),
				@Result(name="input",location = "/WEB-INF/jsp/login.jsp")})
	public String login(){
		HttpServletRequest request = ServletActionContext.getRequest();
		String method = request.getMethod();
		//get请求作为登录页面跳转功能
		if(method.equalsIgnoreCase(REQ_GET)){
			log.d("请求登录页面");
			//这里需要判断一下，如果用户已经登录了，就不用返回登录页面了，而应该直接跳转到登录后的首页

			return LOGIN;
		}

		//post请求作为登录功能
		if(method.equalsIgnoreCase(REQ_POST)){
			HttpParameters parameters = ActionContext.getContext().getParameters();
			String name = parameters.get("loginUser").getValue();
			String pwd = parameters.get("loginPwd").getValue();
			String verify = parameters.get("verify").getValue();

			//参数基本格式校验，判断是空、长度是否符合要求

			//参数的业务格式校验



			//拿到session中存储的验证码、
			String sver = getSessionAttribute(VERIFY_LOGIN)==null?"":getSessionAttribute(VERIFY_LOGIN).toString();
			HashMap resultMap = new HashMap<>();
			if(!sver.equalsIgnoreCase(verify)){
				//验证码不正确，返回
				resultMap.put("success",false);
				resultMap.put("message","验证码不正确");
				ActionContext.getContext().put("result",resultMap);
				return "json";
			}

			//验证码成功，判断信息
			LoginResult loginResult = userService.login(name,pwd);
			if(loginResult.isSuccess()){
				//登录成功
				loginInit(loginResult.getUserModel());
				resultMap.put("success",true);
				resultMap.put("message","登录成功");

				log.i("初始化权限相关信息");
				//登录成功需要获取用户的角色和权限，然后放到session中

				UserModel userModel = loginResult.getUserModel();
				//获取角色信息
				RoleModel roleModel = userModel.getRoleModel();
				//获取角色所拥有的权限列表
				List<PermissionModel> permissionModelList = roleModel.getPermissions();

				for (PermissionModel permissionModel : permissionModelList){
					log.p(permissionModel.getName());
				}

				//v1,将此用户所拥有的权限信息放到session中
				HttpSession session = getSession();
				session.setAttribute(SESSION_PERSSLIST,permissionModelList);


				//v2，系统启动时将角色和权限的关联关系、权限的详情数据加载到了内存，用户登录后只需要根据角色信息去获取权限集合即可

				UserModel u = new UserModel();
				u.setLoginName("aaa");
				u.setLoginPwd("aaaa");
				userService.addNewData(u);

				ActionContext.getContext().put("result",resultMap);
				return "json";
			}else{
//				登录失败
				resultMap.put("success",false);
				resultMap.put("message",loginResult.getMessage());
				ActionContext.getContext().put("result",resultMap);
				return "json";
			}

		}

		return SUCCESS;
	}

	/**
	 * Created by zhouyanchao on 2017/10/18
	 * Descr: 校验方法
	 *
	 */
	@Override
	public void validate(){
		log.i("validate 校验");
		//validate方法是在执行action中的任意方法之前都会调用的

		//可以在此方法中写数据的校验、

	}

	/**
	 * Created by zhouyanchao on 2017/10/18
	 * Descr: 在login方法执行之前执行
	 *
	 * 此方法不能加返回值，否则就不能进入到真正的action处理方法中
	 */
	public void validateLogin(){
		log.i("before login validate");
		//数据校验
		HttpParameters parameters = ActionContext.getContext().getParameters();
		String name = parameters.get("loginUser").getValue();
		String pwd = parameters.get("loginPwd").getValue();

		log.p(name+"..."+pwd);

		//对参数进行校验


		//数据校验没问题，可以继续执行。什么都不需要做，自动会继续执行action的请求


		//校验失败。只要加了个这个错误信息，struts会自动认为验证失败，然后返回input结果，不会进入action的处理方法中
//		addActionError("登录参数校验失败");
		//加在这里边的错误信息，只能通过struts的标签展示
//		addFieldError("name","参数错误");

		//将错误信息放到actionContext中，方便页面展示
//		ActionContext.getContext().put("error","");

	}

	@Action(value = "home",results = {@Result(location = "/WEB-INF/jsp/home.jsp")})
	public String home(){
		log.i("访问登录后的首页");

		return SUCCESS;
	}

	@Action(value = "menus",results = {@Result(type = "json",params = {"root","menus"})})
	public String menu(){
		log.i("获取当前用户菜单");
		//从session中把权限列表取出
		Object object = getSessionAttribute(SESSION_PERSSLIST);
		List<PermissionModel> permissionModels = (List<PermissionModel>)object;

		List<Map> menus = new ArrayList<>();

		for(PermissionModel model : permissionModels){
			HashMap map = new HashMap();
			map.put("id",model.getId());
			map.put("text",model.getName());
			map.put("href",model.getUrl());

			menus.add(map);
		}
		//封装后的数据放到action中
		ActionContext.getContext().put("menus",menus);

		return SUCCESS;
	}


	/**
	 * Created by zhouyanchao on 2017/10/20
	 * Descr: 传统方式，使用response返回文件流信息，在任何框架和servlet中都通用的方法
	 *
	 */
	@Action(value = "download1")
	public String download1(){

		HttpServletResponse response = ServletActionContext.getResponse();
		try {
		// 下载本地文件
			String fileName = "下载测试文件.txt"; // 文件的默认保存名
			//从本地路径读取文件
			String path = ServletActionContext.getServletContext().getRealPath("/static/");
			// 读到流中
			InputStream inStream = new FileInputStream(path+ File.separator+fileName);// 文件的存放路径
			// 设置输出的格式
			response.reset();
			response.setContentType("text/plain");
			response.addHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName,"utf-8") + "\"");
			// 循环取出流中的数据
			byte[] b = new byte[100];
			int len;

			while ((len = inStream.read(b)) > 0)
				response.getOutputStream().write(b, 0, len);
			inStream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}


		return NONE;
	}

	/**
	 * Created by zhouyanchao on 2017/10/20
	 * Descr: struts2的下载文件方法，主方法返回结果即可
	 *
	 * 重点在result配置上
	 * response的设置信息只能在注解或配置中，在方法中写无效
	 */
	@Action(value = "download2",results = {@Result(name = "success",type="stream",params =
			{"contentType","text/plain","inputName","fileInput","bufferSize","100","ContentDisposition","attachment;filename=\"download.txt\""})})
	public String download2(){
/*
		参数说明
				contentType
		内容类型，和互联网MIME标准中的规定类型一致，例如text/plain代表纯文本，text/xml表示XML，image/gif代表GIF图片，image/jpeg代表JPG图片

		inputName
		下载文件的来源流，对应着action类中某个类型为Inputstream的属性名，例如取值为inputStream的属性需要编写getInputStream()方法

				contentDisposition
		文件下载的处理方式，包括内联(inline)和附件(attachment)两种方式，而附件方式会弹出文件保存对话框，否则浏览器会尝试直接显示文件。取值为：

		attachment;filename="struts2.txt"，表示文件下载的时候保存的名字应为struts2.txt。如果直接写filename="struts2.txt"，那么默认情况是代表inline，浏览器会尝试自动打开它，等价于这样的写法：inline; filename="struts2.txt"

		bufferSize
				下载缓冲区的大小
		*/


		HttpServletResponse response = ServletActionContext.getResponse();
		try {
			String fileName = "下载测试文件.txt"; // 文件的默认保存名
			//从本地路径读取文件
			String path = ServletActionContext.getServletContext().getRealPath("/static/");
			// 读到流中
			fileInput = new FileInputStream(path + File.separator + fileName);// 文件的存放路径
		}catch (Exception e){
			e.printStackTrace();;
		}

		return SUCCESS;
	}


	public InputStream getFileInput(){
		return fileInput;
	}

	public void setFileInput(InputStream fileInput) {
		this.fileInput = fileInput;
	}
}
